home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacTech 1 to 12
/
MacTech-vol-1-12.toast
/
Reference
/
the cmsp digests ('94-'97)
/
csmp digest Vol 3 No 109
< prev
next >
Wrap
Text File
|
1995-09-11
|
54KB
|
1,334 lines
C.S.M.P. Digest Mon, 11 Sep 95 Volume 3 : Issue 109
Today's Topics:
C to Pascal FAQ (1 of 2)
C to Pascal FAQ (2 of 2)
Can't Deactivate Default Item??
MacTCP Question
The Comp.Sys.Mac.Programmer Digest is moderated by Francois Pottier
(pottier@clipper.ens.fr).
The digest is a collection of article threads from the internet newsgroups
comp.sys.mac.programmer.help, csmp.tools and csmp.misc. It is designed for
people who read news semi-regularly and want an archive of the discussions.
If you don't know what a newsgroup is, you probably don't have access to
it. Ask your systems administrator(s) for details. If you don't have access
to news, you may still be able to post messages to the group by using a
mail server like anon.penet.fi (mail help@anon.penet.fi for more
information).
Each issue of the digest contains one or more sets of articles (called
threads), with each set corresponding to a 'discussion' of a particular
subject. The articles are not edited; all articles included in this digest
are in their original posted form (as received by our news server at
nef.ens.fr). Article threads are not added to the digest until the last
article added to the thread is at least two weeks old (this is to ensure that
the thread is dead before adding it to the digest). Article threads that
consist of only one message are generally not included in the digest.
The digest is officially distributed by two means, by email and ftp.
If you want to receive the digest by mail, send email to listserv@ens.fr
with no subject and one of the following commands as body:
help Sends you a summary of commands
subscribe csmp-digest Your Name Adds you to the mailing list
signoff csmp-digest Removes you from the list
Once you have subscribed, you will automatically receive each new
issue as it is created.
The official ftp info is //ftp.dartmouth.edu/pub/csmp-digest.
Questions related to the ftp site should be directed to
scott.silver@dartmouth.edu.
-------------------------------------------------------
>From catambay@aol.com (Bill the Cat)
Subject: C to Pascal FAQ (1 of 2)
Date: 23 Aug 1995 02:00:14 GMT
Organization: MacPascal Mailing List
Here is a FAQ for converting C code to Pascal code which I found awhile
back. Hope it helps some of you.
-- cut here --
_________________________________________________________________________
The Pascal Programmer‘s Guide to Understanding ‘C‘
by Ken Gladstone
Most of the articles that we receive here at MacTech Magazine use source
code that is written in C. We have had a number of readers request that
we either publish more articles that use Pascal, or that we provide Pascal
translations of our source code listings. Since we can‘t force authors to
use Pascal, and since we really don‘t want to translate every piece of C
code that we publish, our reply has always been “You should be reading the
articles to learn the programming concepts, and it shouldn‘t matter what
language we use in the listings. (Or you should submit more Pascal-based
articles!)“ Well, we have had several readers respond saying that this
would be fine, except that they are unable to read C - a valid complaint.
With this article, I aim to remove that as a valid complaint. This
article is designed to teach Pascal programmers how to understand C code
listings. Although since my Pascal is a little rusty and I now program
primarily a C, perhaps I should have written an article entitled “The ‘C‘
Programmer‘s Guide to Remembering Pascal!“ This article is in no way
intended to be a complete C reference, but is simply intended to help you
Pascal programmers understand the C listings that you see in our magazine
or elsewhere.
Let me provide a little information on the history of C and some of its
incarnations. The original Bible for C programmers is a book called “The
C Programming Language“ by Brian Kernighan and Dennis Ritchie, published
by Prentice-Hall. The book is often refered to as “Kernighan and
Ritchie,“ or simply “K&R.“ If after reading this article you want to see
the true original C reference, I suggest you pick up a copy of K&R. Since
that time, the C language has been expanded and standardized, resulting in
ANSI C. In addition to supporting ANSI C, most current compilers have
their own extentions to the language. At times, I will refer to Mac
specific aspects of the C language. So, let‘s begin:
___________________________________________________________
COMMENTS
We‘ll start with comments because they are easy (and also because K&R
start with them in the reference section of their book).
/* A forward slash followed by a star signifies the beginning of a C
comment. Comments can span multiple lines, and are ended by a star and
another slash */
There is a second form of comment that is not in K&R C, but that is
supported in many C compilers, including MPW and Think C. Two forward
slashes signify a comment that continues until the end of the line. Here
are three uses of that style comment:
// A one line comment
LineOfCode(ThisIs); // Comment at end of a line of code
// LetsCommentOut += ThisLineOfCode;
________________________________________________________________
IDENTIFIERS
Both C and Pascal have similar rules about naming identifiers: you can
use letters, digits and the underscore character, and the first character
cannot be a digit. But while Pascal identifiers are not case sensitive, C
identifiers are: variable, Variable and VARIABLE are three different
identifiers. In fact, in C pretty much everything is case sensitive.
OPERATORS
Operators can be a great source of confusion because both C and Pascal use
many of the same special characters, but with vastly different meanings.
The following table summarizes the operators. I have highlighted the ones
that I feel may cause Pascal programmers the most confusion in reading C.
The operators are presented in K&R‘s reference order:
C Operator Pascal Equiv. Description
- --------------------------------------------------------------- --
struc.field struc.field Obtain a field of a record (structure).
ptr->field ptr^.field Obtain a field of a pointer to a record.
* ptr ptr^ Dereference a pointer
& variable @ variable Return pointer to (address of) a variable
- expr - expr Unary negation
! expr NOT expr Logical negation
~ expr BNOT( expr) Bitwise negation (one‘s complement)
++ var var := var + 1 Pre-increment (see notes below)
-- var var := var - 1 Pre-decrement (see below)
var ++ var := var + 1 Post-increment (see below)
var -- var := var - 1 Post-decrement (see below)
(type)expr type(expr) C: Type casting, Pascal: type coercion
sizeof expr Sizeof(expr) C: sizeof operator, Pascal: Sizeof function
sizeof(type) Sizeof(type) C: sizeof operator, Pascal: Sizeof function
e1 * e2 e1 * e2 Mutiplication
e1 / e2 e1 / e2 ( e1 DIV e2 ) Division (see below)
e1 % e2 e1 MOD e2 Remainder (modulo operator)
e1 + e2 e1 + e2 Addition
e1 - e2 e1 - e2 Subtraction
e1 << e2 BSL(e1,e2) C:Left shift operator, Pascal:left shift func.
e1 >> e2 BSR(e1,e2) Right shift
e1 < e2 e1 < e2 Relational “less than“ comparison
e1 > e2 e1 > e2 Relational “greater than“ comparison
e1 <= e2 e1 <= e2 Relational “less than or equal“ comparison
e1 >=e2 e1 >= e2 Relational “greater than or equal“ comparison
e1 == e2 e1 = e2 Equal to comparison
e1 != e2 e1 <> e2 Not equal to comparison
e1 & e2 BAND( e1, e2) Bitwise “and“
e1 ^ e2 BXOR( e1, e2) Bitwise “exclusive or“
e1 | e2 BOR( e1, e2) Bitwise “or“
e1 && e2 e1 & e2 Logical “and“
e1 || e2 e1 | e2 Logical “or“
e1 ? e2 : e3 see below The ternary “conditional“ operator
var = expr var := expr Simple assignment
var += expr var := var + expr Add then assign
var -= expr var := var - expr Subtract then assign
var *= expr var := var * expr Multiply then assign
var /= expr var := var / expr Divide then assign
var >>= expr var := BSR(var,expr); Shift right then assign
var <<= expr var := BSL(var,expr); Shift left then assign
var &= expr var := BAND(var,expr); Bitwise “and“ then assign
var ^= expr var := BXOR(var,expr); Bitwise “exclusive or“ then assign
var |= expr var := BOR(var,expr); Bitwise “or“ then assign
expr , expr see below Comma operator
Some important things to note: In C, the single equal sign is used for
assignment, while in Pascal, the single equal sign is used for “equal to“
comparison. C uses two equal signs for “equal to“ comparison. In C, the
single amperand ‘&‘ is used both for the bitwise “and“ operation (a binary
operator) and for determining the address of a variable (a unary
operator). In C, the asterisk ‘*‘ is used both for multiplication (binary
operator) and for dereferencing a pointer (unary operator). In C, parens
are used both for determining order of operations, and also for type
coercion (called casting in C). There are several C operators that
translate to functions in Pascal (bitwise negation, sizeof, bit shifting,
etc.). C does not have a built-in exponentiation operator to correspond
to Pascal‘s ‘**‘ operator.
Unlike Pascal, C does not have two separate division operators. It
performs integer division if both operators are of intergral types.
My table doesn‘t tell the whole story of the very useful pre- and
post-increment (and decrement) operators. These operators are probably
best understood with an example. So here is a fragment of C code:
a = ++b;
c = d++;
The Pascal equivalent is:
b := b + 1;
a := b;
c := d;
d := d + 1;
Both the pre and post increment operators will increment the given
variable. The difference is when. The pre-increment operator increments
the variable before using the variable‘s value. The post-increment
operator uses the existing value and then increments the variable.
The table doesn‘t explain the C ternary “conditional“ operator, ‘a ? b :
c‘. If the first operand evaluates to non-zero, then the “conditional“
operator evaluates to its second operand, otherwise it evaluates to its
third operand. This operator is also probably easiest to understand by
example. Here is some C code:
result = a ? b : c;
And the Pascal equavalent:
IF a<>0 THEN result := b ELSE result := c;
The “comma“ operator is another unusual one in C. It is used to group
expressions (where you would usually expect to see only one expression)
and it evaluates to the value of the right expression. Once again, here
is a C example (calling a function that takes three parameters):
result = myFunction( a, (b=3, b+2), c);
and the Pascal equvalent:
b := 3;
result: = myFunction( a, b + 2, c );
Both of these code fragments end out assigning 3 to b, and end out passing
5 as the second parameter to myFunction.
___________________________________________________________________
CONSTANTS
A sequence of digits generally signifies a decimal constant. If the
sequence begins with a 0 (zero digit), then the constant is octal. If the
sequence begins with 0x or 0X, then the constant is hexadecimal, and can
also contain the letters a-f or A-F. If the sequence ends in the letter
ell (l or L), the constant is an explicit long integer. For example 123L
is of C type long (Pascal type longint).
A character enclosed in single quotes represents a constant of the ACSII
value of the character. For example, '!' is the same as 33. Certain
special character constants can be represented with the following escape
sequences.
Sequence Meaning
- --------------------------------------------------------------- --
\n The newline character (character 10)
\t The tab character (character 9)
\b The backspace character (character 8)
\r Carriage return (character 13)
\f Form feed (character 12)
\\ Backslash
\' Single quote
\ddd The octal constant represented by the 1, 2 or 3 digits ddd.
_____________________________________________________________________
PROGRAM STRUCTURE
Unlike Pascal, C does not differentiate between procedures and functions -
in C, everything is a function. But C functions are not required to
return values, so a C function that does not return a value is like a
Pascal procedure. C uses the keyword void as the return type for a
function that does not return a value. C also uses the keyword void as
the parameter list for functions which take no parameters. Unlike Pascal,
C does not allow nested functions. All C functions are at the same level.
C does not have an equivalent to the Pascal PROGRAM keyword. Instead, C
knows where to start executing by looking for a function called main.
main is not a reserved C keyword, it is just a C compiler convention to
generate code that starts by executing a function called main. Pascal
uses BEGIN and END to create a block of statements (a compound
statement). C uses curly braces, so ‘{‘ is equivalent to BEGIN and ‘}‘ is
equivalent to END.
Pascal only needs semicolons between two statements - it doesn‘t need one
on the last statement of a block (compound statement), nor in constructs
with just a single statement. C needs a semicolon after every statement.
However, C does not put a semicolon after the end of a block, nor does it
put a period at the end of a unit. C compilers just keep parsing a source
files until reaching the EOF.
Using the preceeding rules, here is an example of a C function with no
return value, and its Pascal equivalent procedure. First the C version:
void myProc( long myFirstParam, char mySecondParam )
{
/* Here we have some code that does something */
}
Now the Pascal version:
procedure myProc(myFirstParam: LONGINT, mySecondParam: CHAR);
BEGIN
(* Here we have some code that does something *)
END;
Pascal returns its function values by assigning a value to the function
name. C returns a value by using its return statement. Here is an
example of a C function that takes no parameters and that returns a double
precision floating point value, and then its Pascal equivalent:
double myFunc( void ) /* C version */
{
return 3.14;
}
function myFunc : DOUBLE; (* Pascal Version *)
BEGIN
myFunc := 3.14
END;
_____________________________________________________________________
VARIABLE DECLARATIONS AND SCOPE
C makes a distinction between declaring and defining a variable. A
declaration describes the characteristics of a variable, but may or may
not create the actual storage for the variable. A definition will alway
create the actual storage. While Pascal separates its declarations into
type, const and var sections, C specifies this information individually
for each declaration. C declarations can occur either within the body of
an individual function, or outside of any function. Generally, a variable
declared inside a function can only be seen within that function, and only
uses storage space while the program is executing the function.
Generally, a variable declared outside of any function lives for the
entire execution of the program, and is visible everywhere. But C
provides some modifiers that alter those rules. Here is an example C
variable declaration to show the various parts of a declaration:
static unsigned long myLongVar[2][3],
* myPointerVar = & myLongVar[1][0];
The word static is a “storage class“ specifier. Storage class keywords
are optional, and tell the compiler such things as where the variable
actually lives and the width of its scope. The unsigned and long keywords
are “type“ specifiers. They tell the compiler the type of the variable.
myLongVar and myPointerVar are the comma-separated list of names of
variables to declare. The [2][3] after myLongVar signifies that we are
declaring a 2 by 3 array (with indexes starting at zero) of unsigned
longs. The star before myPointerVar means that the variable is actually
of type pointer to the base type unsigned long integer, and the = &
myLongVar[1][0] is an initializer that assigns an initial value to the
variable. In this case myPointerVar is initialized to the address of one
of the elements of myLongVar (i.e. initialized to point to
myLongVar[1][0]).
Let‘s start with the various “storage classes.“ The following table
describes the storage classes (and ANSI and Apple extension type
qualifiers):
Keyword Description
auto auto is the implied type for variables that are declared within
the body of a function. And since it is implied, you will
probably never see the keyword actually used. It means
that the
variable is created on the stack each time the function is
called, and that it vanishes each time the function is exited.
The variable uses no storage at any other time, and cannot
been seen outside the scope of the enclosing function. A
recursive function with an auto variable would have a separate
instance of the variable for each level of recursive depth.
register register variables are a variation of auto variables.
They have
the same scope and lifespan, but the register keyword requests
that the compiler try to store the variable in a register (for
faster access) instead of on the stack. Each compiler has its
own rules about the number and type of variables that can be
placed in registers, and compilers generally ignore the
register
keyword if it is used for too many variables, or for variables
that are too large to store in a register.
volatile This is an ANSI extension. Many compilers‘ optimizers will
automatically try to place auto variables in registers. The
volatile keyword instructs the optimizer not to do this,
but to store the variable on the stack.
static The static keyword has two uses: First, a static variable
defined inside a function is local to that function, but
retains
its value (and uses non-stack storage) throughout the life of
the program. A recursive function that contains a static
variable would only ever have a single instance of the
variable.
Second, a static variable defined outside of a function
body has
its scope limited to the file that contains it - it cannot be
seen or used by other source files. Similarly, the static
keyword can be applied to function names to prevent them from
being seen or called by other files.
const This is an ANSI extension. The const qualifier is used to
specify that the given identifier is a constant that cannot be
changed, and is similar to identifiers declared in a Pascal
const section. It modifies the word that follows it, so it can
be used in various ways:
const int myInt = 5; /* myInt can‘t change value */
// The following 3 examples are pointers
// to characters
const char *p; /* p can change, but what it
points to can't */
char *const p = "Hi"; /* p can't change, but what
it points to can */
const char *const p; /* Neither can be changed */
extern The extern keyword is used to declare (without allocating any
storage) the characteristics of a variable which is actually
defined (with allocated storage) elsewhere. The most common
use is to define a variable in one file (outside of the body
of any function), and then to have an external declaration of
that variable in a second file. In this way, code in multiple
files can share variables without passing them as function
parameters. This declaration concept can be applied to
functions as well as variables. When a function is declared
this way, the result is commonly referred to as a “function
prototype.“ This usage is similar to Pascal‘s FORWARD
directive.
typedef typedef is not used for declaring variables - it is used for
defining types (similar to identifiers in a Pascal type
section). So for typedefs, the name given at the end of the
declaration is the desired name for the type instead of the
desired name for a variable. Like extern, typedef does not
create any storage.
pascal This is an Apple extension. The pascal keyword is used with
function declarations, and is used for allowing C code to call
Pascal code, and vice versa. The pascal keyword tells the
compiler that the given function uses Pascal‘s calling
conventions. It can be used for declaring external functions
that are written in Pascal (such as all the Macintosh toolbox
calls), or it can be used for functions that are written in
C but that will be called from a Pascal file. One of the
differences between C and Pascal function calling is that C
pushes function arguments onto the stack from right to left,
and Pascal pushes function arguments from left to right.
After the optional storage class specifiers, the next component of a
declaration is the “type“ section. The following table describes C‘s
various standard variable types:
C Type Pascal Equivalent Description
- ---- ---------------------- ----------------------------------- ---
int integer or longint Signed integer variable type.
This is supposed to be the “natural“ integer
size for the CPU. MPW C ints are 4 bytes,
Think C ints can be either 2 or 4 bytes,
selected by compiler option.
char char One byte character variable type. Note that
C chars are signed (-128..127) but that Pascal
chars are unsigned (0..255). See unsigned
keyword below.
short integer 2 byte signed integer variable type (on the Mac).
long longint 4 byte signed integer variable type (on the Mac). Can also
be used in conjunction with the word double to
signify an even longer float type (see
extended below).
comp comp, computational Apple Extension. An 8 byte SANE
signed
integer.
float real, single 4 byte floating point variables (on the Mac).
double double 8 byte floating point variables (on the Mac).
extended extended Apple Extension. It means the same as
long double, and signifies either a 10 or
12 byte floating point value (depending
upon whether 68881 compiling is turned on).
struct record Used for variables with multiple fields. The
field declarations are enclosed by curly
braces, and each field declaration looks
like a regular variable declaration.
union variant record Used for variables with a choice of types (see
below). These look like structures, and are
accessed in the same way, but are quite
different.
enum TYPE=(val1,val2,ä) Enumerated type.
unsigned This modifier is used to specify unsigned
versions of ints, chars, shorts, and longs.
For example, an unsigned char is a one byte
unsigned character variable, equivalent to a
Pascal char. If used by itself, it means
unsigned int.
signed This modifier is used to signify
signed
versions of the integer types. This is the
default in most compilers.
void This type has a few uses. When used as the
return type for a function, it signifies that
the function does not return any value
(similar to a Pascal procedure). When used as
the parameter list of a function, it signifies
that the function does not take any
parameters.
When used with a star (void *) it signifies a
generic pointer type that can point to any
base type.
Now that we‘ve covered the elements of declarations, and since tables and
syntax descriptions can only go so far, here is an example that
demonstrates many of these “variable declaration“ concepts in action. The
example consists of two (very contrived) files that show a bunch of common
C constructs.
/*************** Start of File1.c *****************/
/*
* This file starts by defining some global variables
* and declaring some new variable types.
*/
int globalToTheWorld = 10; // Any code can access this var
static int globalToThisFile = 1; // Only for code in this file
/*
* This declaration does not create any storage nor any
* variables. It just defines a new 'uchar' variable type.
*/
typedef unsigned char uchar; // 'uchar' is a new type
/*
* Define a structure variable (like a Pascal record).
* The structure consists of two fields.
*/
struct
{ // Fields are enclosed by curly braces
int anInteger; // This is one field
int * pointerToAnInteger; // This is another field
} myRecordVar; // This is the variable
/*
* It is common to combine a 'typedef' with a 'struct' to
* define a new variable type that is a structure (record).
*/
typedef struct
{
int anInt;
uchar aUchar;
} myStructType; // No storage, just a type
/*
* Declare a function that lives 'extern' elsewhere
* (in this case, in the Macintosh toolbox).
* Since there is no code here, the 'extern' keyword
* is implied and is not actually necessary. This
* line is generally called a function prototype, and
* it is similar to a pascal FORWARD directive.
* the 'pascal' keyword tells the 'C' compiler to use
* Pascal function calling rules for this function.
* You actually won't have to prototype the toolbox
* routines, as you'll see when we discuss the
* C preprocessor.
*/
extern pascal void SysBeep( short Duration );
/*
* Now that we have some types and some global variables,
* here is some code. This first function has the static
* keyword, and hence cannot be called from other files.
* 'void' signifies that it takes no parameters.
*/
static float FunctionForThisFileOnly( void )
{
int anAutoIntOnTheStack; // an implied auto, on the stack
register int inARegisterForSpeed = 2;
// This next variable retains its value from call to call
static int howManyCalls = 0;
myStructType aStructure;
myStructType * ptrToStruct;
void * ptrToAnything = & globalToTheWorld;
// each time we're called, increment this count
++ howManyCalls;
ptrToStruct = & aStructure; // ptr now points to the struct
aStructure.anInt = 7; // We can access members
// from the var...
ptrToStruct->aUchar = 'c'; // ...or from a ptr to the var.
// A pointer can be assigned the address of a variable
myRecordVar.pointerToAnInteger = & anAutoIntOnTheStack;
/*
* A star defererences a pointer, so this statement
* actually assigns 7 to the 'anAutoIntOnTheStack' var.
*/
* myRecordVar.pointerToAnInteger = 7;
/*
* The next two statements are like the last two, but note
* that to access what a void pointer points to, you must
* first cast (coerce) it to a valid type. In this case,
* we cast it to be a pointer to an integer, and then
* dereference it.
*/
ptrToAnything = & anAutoIntOnTheStack;
* (int *)ptrToAnything = 6;
inARegisterForSpeed
= globalToThisFile + globalToTheWorld - howManyCalls;
anAutoIntOnTheStack = inARegisterForSpeed * 2;
// The function evaluates to (returns) this:
return anAutoIntOnTheStack / 2.0;
}
/*
* This second function is not static,
* so it can be called from other files.
* the two 'void' keywords signify that it
* returns no value (like a Pascal procedure)
* and that it takes no parameters.
*/
void GlobalDoubleBeep( void )
{
SysBeep( 1 );
SysBeep( 1 );
}
/****************** End of File1.c ************************/
-- cut here --
_____________________________________________________________________
Bill Catambay
Pascal Programmer on Macintosh and Open VMS
/>
// The purpose of software engineering
(//////[O]>=========================================-
\\ is to manage complexity, not to create it.
\>
____________________________________________________________________
---------------------------
>From catambay@aol.com (Bill the Cat)
Subject: C to Pascal FAQ (2 of 2)
Date: 23 Aug 1995 02:01:32 GMT
Organization: MacPascal Mailing List
-- cut here --
/******************** Start of File2.c ********************/
/*
* Because of the 'extern' keyword here,
* this declaration does not create any storage,
* it just allows code in this file to use a variable
* that is actually defined in another file (file1.c).
*/
extern int globalToTheWorld;
/*
* This is a function prototype, like in file1.c,
* but here I've left off the implied 'extern'.
*/
void GlobalDoubleBeep( void );
static float LocalFunction( void )
{
/*
* A union variable looks like a structure variable,
* and it is accessed in the same manner. But instead
* of containing enough storage for ALL of its fields,
* it can only contain one of them at any given time.
* Its size is determined by the size of its largest
* field. Generally, something else in the code keeps
* track of what kind of value is currently stored in
* a given union variable. This is similar to having a
* variant record (a case inside a record) in Pascal.
*/
union
{
float CanBeFloat;
long CanBeLongInt;
char CanBeChar;
} schizophrenia;
enum {black, brown, red, orange, yellow, green,
blue, violet, grey, white} color;
/*
* The numbers in curly braces are initial
* values for this array. And since no size
* for the array is provided in the square
* brackets, the compiler uses the initializer
* list to set the array size -- in this case 3.
*/
int Array[] = { 7, 12, 6 };
/*
* Now that we've declared our variables, here's the code:
*/
Array[0] = 2; // An array of size 3 uses...
Array[1] = 5; // indexes 0, 1, and 2.
Array[2] = 17;
color = green;
++ globalToTheWorld; // Use a variable from another file
GlobalDoubleBeep(); // Use a function from another file
schizophrenia.CanBeFloat = 1.234;
/*
* If we assign to a different field of the union, we
* wipe out the CanBeFloat value that we just put in.
*/
schizophrenia.CanBeLongInt= 123456789;
/*
* Here we're interpreting a long as a float,
* so the result is basically meaningless!
*/
return schizophrenia.CanBeFloat;
}
______________________
PARAMETER PASSING
One key difference between C and Pascal is that C always passes parameters
by value, never by reference. Therefore, you may be wondering how a C
function can ever modify a passed in parameter. It can‘t - but you can
accomplish the same thing by passing a pointer to the value you wish to
modify, and having the function modify the pointed to value. Here is an
example:
/************************ C Version *************************/
void doubleIt( int * pointerToIntParam )
{
(*pointerToIntParam) *= 2;
}
int main()
{
int myInt = 3;
doubleIt( & myInt );
return myInt;
}
/******************** End of C Version **********************/
(********************* Pascal Version ***********************)
Program myProgram;
Var
myInt: INTEGER;
Procedure doubleIt( var IntParam: INTEGER );
begin
IntParam := IntParam * 2
end;
begin
myInt := 3;
doubleIt( myInt );
end.
(****************** End of Pascal Version *******************)
OLD VERSUS NEW FUNCTION DECLARATIONS
So far, I‘ve been showing functions as follows:
int MyFunc( int a, char b, float c )
{
/* Code goes here */
}
This way of writing functions is an ANSI extension that allows C to
perform parameter type checking when calling a function. Things weren‘t
always so nice. In the original K&R C, functions were written as follows:
int MyFunc( a, b, c )
int a;
char b;
float c;
{
/* Code goes here */
}
In original C compilers, when calling a function, there was no checking of
parameter types, or often even of the number of parameters! In old C, you
could write a call to a function before it had ever been defined, declared
or mentioned in any way! Now, C compilers have much stronger
type-checking. For example, Think C has a compiler option to require you
to write a function prototype for every function.
________________________________________________________________________
FLOW CONTROL
So far, all of the examples that I‘ve shown execute code sequentially - in
fact, I‘ve only shown declarations, assignment statements, function calls,
and function return statements. Like Pascal, C has various loops and
other constructs to control the flow of code. We‘ll start with the while
loop. The while loop in C is nearly identical to the one in Pascal,
except that it needs parens around the test expression and it doesn‘t have
a DO keyword. Examples:
while ( i < j ) i *= 2; // First C example
while i < j DO i := i * 2; {Pascal Equiv.}
while ( i < j ) // C example w/compound statement
{
sysBeep( 1 );
i *= 2;
}
while i < j DO {Pascal Equiv.}
begin
sysBeep( 1 );
i := i * 2
end;
Next we have the C do statement. This is a loop with the test at the end
of each iteration, like the Pascal REPEAT statement, but the sense of the
while test at the end is the opposite of the Pascal UNTIL test. Unlike
the Pascal version, the C version needs braces if the loop contains a
compound statement. And again, the while condition needs parens.
Example:
do // C version
{
sysBeep( x );
++ x;
}
while ( x != 10 );
REPEAT {Pascal equiv.}
sysBeep( x );
x := x + 1
UNTIL x = 10;
Next we have the for loop. The for loop in C is far more general than the
one in Pascal. It looks like this:
for ( expr1; expr2; expr3 )
statement;
What it does is this: expr1 is an initialization that is performed before
executing the loop for the first time. expr2 is a test that is performed
before each iteration. As long as expr2 evaluates to non-zero, the
looping continues. expr3 is a statement that is performed at the end of
every iteration. C does not limit loops to simple count up and count down
types. Any or all of the three expressions may be omitted, but the
semicolons must remain. Any C for loop can be rewritten as follows:
expr1;
while( expr2 )
{
statement;
expr3;
}
Example:
for ( i = 10; i != 0; --i ) // C example
DoIt( i );
for ( i = 10; i; --i ) // An equivalent variation
DoIt( i );
i = 10; // Another equivalent variation
while ( i )
{
DoIt( i ); // Could use pre or post decrement
-- i;
}
i = 10; // Yet another equivalent variation
while ( i )
DoIt( i-- ); // Must use post decrement
FOR i := 10 DOWNTO 0 DO {Pascal equivalent}
DoIt( i );
The C if statement is very similar to the Pascal version: The else clause
is optional, and the statements can be either simple or compound. The
only difference is that C needs parens around the expression, it doesn‘t
use the THEN keyword, and as always, every statement needs a semicolon.
Example:
if ( condition ) // C
DoOneThing();
else
{
DoAnother();
AndAnother();
}
IF condition THEN {Pascal version}
DoOneThing
ELSE
BEGIN
DoAnother;
AndAnother
END
C has a case statement that is very similar to the Pascal version. An
example should suffice:
switch ( x ) // C version
{
case 1:
case 2:
DoTheOneOrTwoThing();
break; // Must explicitly leave each case
case 3:
DoTheThreeThing();
AndTheOtherThreeThing(); // Purposely fall through
case 7:
DoTheThreeAndSevenThing();
break;
default:
DoTheDefaultThing();
}
CASE x OF { Pascal Version }
1, 2: DoTheOneOrTwoThing;
3: BEGIN
DoTheThreeThing;
AndTheOtherThreeThing;
DoTheThreeAndSevenThing; { In Pascal, we need this twice }
END;
7: DoTheThreeAndSevenThing; {In Pascal, we need this twice}
OTHERWISE
DoTheDefaultThing
{CASE} END;
The previous example used the C break keyword. This keyword is like the
Pascal Leave statement, and can be used to break out of the innermost
while, do, for, or switch. C also has a continue keyword that like the
Pascal Cycle statement. It skips to the next iteration of the innermost
while, do or for loop.
Finally, C also has the dreaded goto statement (nothing seems to split
programmers into warring factions as well as a goto statement does).
Unlike in Pascal, you don‘t declare labels in C, you just stick ‘em in the
code, and they follow the same syntax as other identifiers. Example:
{ // C
MyLabel:
x := Function();
if ( x == 10 ) goto MyLabel;
}
LABEL 333; { Pascal }
BEGIN
333: x := Function;
IF x=10 THEN GOTO 333
END
________________________________________________________________________
LIBRARY FUNCTIONS
Standard C has oodles of library functions, such as malloc() and fread(),
that you would use if you were programming on any computerä unless you are
programming on a Macintoshä which you are. So for the most part, you will
use calls like NewPtr() and FSRead() instead. You‘ll need to look at your
C compiler manual if you are interested in the standard C libraries.
STRINGS
Amazingly enough, standard C doesn‘t really provide much built-in language
support for strings. There are several standard C library functions that
process strings, but no real string type or operators. C handles strings
as simple arrays of the char type. In general, you would create a string
in one of the following ways:
{
char myString[100]; // 100 bytes of storage
char Another[] = "LetTheCompilerCountTheSize";
char * ptrToString;
ptrToString = NewPtr( 100 );
}
C also has a different way of representing strings than the Pascal way.
Instead of having a length byte followed by a number of characters, C
starts immediately with characters, and the string is considered to
continue until the occurrence of a zero byte. So this declaration:
char myString[] = "Foo";
creates four bytes of storage. It fills the first three with the word
"Foo" and puts a zero byte in the fourth. This convention allows strings
of arbitrary length.
This string representation doesn‘t fit well with Pascal nor with the Mac
toolbox, but don‘t despair. C only uses this convention in two places:
In string constants (like the "Foo" shown above) and in its library
functions. The Mac solves the second problem by shunning the C library
that is used by the rest of the world, in favor of its own toolbox. And
the compilers on the Mac solve the first problem by introducing an
ingenious extension, the \p escape sequence. Here is an example:
char pascalString[] = "\pFoo";
This causes the compiler to insert a Pascal-style length byte at the
beginning of the string. It still generates a zero-byte at the end,
however. So the above declaration would use five bytes: The first byte
contains a 3 (for the Pascal length), the next three bytes contain the
string, and the final byte contains the C-style zero byte. So
pascalString can be used as a Pascal string, and (pascalString+1) or
&pascalString[1] can be used as a C string.
_______________________________________________________________________
THE PREPROCESSOR
C compilers include a preprocessor step that reads in the source file,
expands macros, and then writes back a temporary file that is fed into the
actual compiler. Keep in mind that preprocessor commands are purely
compile-time, not run-time operations. They are similar to Pascal {$ä }
compiler directives. Instead of being embedded within comments, C
preprocessor instructions begin with a number sign ‘#‘. Here is a
(somewhat contrived) code fragment that includes many of the common
preprocessor instructions:
#include <stdio.h>
#include "myheader.h"
#define DEBUG // Delete this line before shipping program.
#define PI 3.14159
#define square(a) ( ( a ) * ( a ) )
#define cube(a) ( ( a ) * square( a ) )
#define max(a,b) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
#pragma segment mySegment
double MaxSurfaceOrVolume( double radius )
/*
* This is a strange function which will return either the
* surface area or the volume of a sphere, whichever is
* larger, for a given radius.
*/
{
#ifdef DEBUG
printf( "Hey, we're in the MaxSurfaceOrVolume function" );
#else
printf( "Hey, we're running the non-debug version" );
#endif
#if 0
I could have a bunch of lines of code in here, and they
wouldn't ever be executed, or even compiled.
#endif
return max( 4 * PI * square( radius ),
4.0/3.0 * PI * cube( radius ) );
}
The following table describes the preceding preprocessor statements:
Preprocessor Statement Meaning
- --------------------------------------------------------------
#include <stdio.h> Similar to the Pascal {$I filename} directive. Paste
the contents of the included file into here as if they
had actually been typed into this file. The angle
brackets generally tell the compiler to look for the
include file in its list of “system“ file folders.
Include files are generally named with a .h at the end.
They generally consist of things like typedefs, global
variable definitions, function prototypes, preprocessor
macros, etc. The Mac compilers provide header files
that prototype all the toolbox functions so you don‘t
have to.
#include "myHeader.h" Same as above, but look in the list of “user“ file
folders instead of system file folders.
#define DEBUG Similar to the Pascal {$SETC DEBUG = 1} directive.
Define the existence of a preprocessor variable. The
existence of the variable can be checked later.
#define PI 3.14159 A simple text substitution. Replace all future
occurences of PI with 3.14159.
#define square(a) ((a)*(a))
A substitution that takes parameters. Keep in mind
that while a macro like this may look like a function
call, it is purely text substitution, and therefore
incurs none of the overhead of a function call.
#pragma segment mySegment
The #pragma feature allows compiler specific
instructions that are not actually part of the C
language. Each compiler has its own pragmas. They
are used for such things as turning optimizations on
and off, disabling compiler warnings, or in this case,
telling the compiler in what code segment to put this
code. They perform many of the same functions as the
miscellaneous Pascal {*ä } directives.
#ifdef DEBUG Similar to {$IFCä} in Pascal. The subsequent statements
will only be compiled if the variable is defined.
#else Similar to {$ELSEC}. The subsequent statements will
only be compiled in the “else“ case of the preceding
#if.
#endif Similar to {$ENDC}. Ends a preprocessor #if or #ifdef
construction.
#if 0 This is a quick way to disable a chunk of code. Change
it to #if 1 to re-enable.
___________________________________________________________________________
SUMMARY
You should now know enough C to be able to read C code listings. If you
would like to get some more practice at seeing the differences between C
and Pascal, you may wish to check out Dave Mark‘s first few “Getting
Started“ articles. Dave wrote both a C and Pascal version for all of his
programs in the 1992 columns. And while we didn‘t print all of the
listings in the magazine, we did include them in the source code disks and
in our CD-ROM. Beyond that, you‘ll probably have to break down a buy a
couple of C books.
Million dollar (no, we won‘t pay you, even if you have a good answer!)
bonus question: K&R say that the term define is used when actually
creating storage for a variable, and that the term declare is used when
describing the characteristics of a variable (and only possibly creating
storage). So why is it that type declarations, which allocate no storage,
are spelled typedef (short for type definition) instead of being spelled
typedecl? Perhaps this has been discussed somewhere before, but not that
I‘ve seen. Personally, I like the C keyword, and think that K&R have the
define and declare terms backwards throughout their book!
-- cut here --
_____________________________________________________________________
Bill Catambay
Pascal Programmer on Macintosh and Open VMS
/>
// The purpose of software engineering
(//////[O]>=========================================-
\\ is to manage complexity, not to create it.
\>
____________________________________________________________________
---------------------------
>From Robert Nickel <rnickel@makesense.com>
Subject: Can't Deactivate Default Item??
Date: 22 Aug 1995 20:27:53 GMT
Organization: BEST Internet (415) 964-2378
I've created a dialog box with an OK button, which I would like to:
a) set as the default button and
b) deactivate under certain conditions.
I set the button as the default with
SetDialogDefaultItem( dialog, ok );
and deactivate it with
GetDItem( dialog, ok, &itemType, &oKButtonHdl, &itemRect );
HiliteControl( (ControlHandle)oKButtonHdl, kButtonInactive );
Only trouble is, the deactivation only works when I comment out the
default item line. If I leave the default item line in, then the button
stays active the whole time the dialog is open.
Thanks in advance for any help.
-Bob
http://www.makesense.com/bob.shtml
+++++++++++++++++++++++++++
>From Charles B. Cranston <zben@ni.umd.edu>
Date: 22 Aug 1995 21:25:52 GMT
Organization: Network Infrastructures UMD CSC
In article <41dek9$gsr@news1.best.com> Robert Nickel
rnickel@makesense.com writes:
> SetDialogDefaultItem( dialog, ok );
> the deactivation only works when I comment out the
> default item line. If I leave the default item line in,
> then the button stays active...
Yeah, I ran into that too. This is how I programmed
around the problem (see case activateEvt at the end):
// The HiliteControl call here is a serious kluge:
// It appears that calling SetDialogDefaultItem sets a flag that
// causes ModalDialog to enable the Add button (DAQADD) under all
// circumstances in the StdFilterProc routine. To get Add NOT to
// be lit-up when the dialog comes up, I had to un-hilite it AFTER
// the first call to StdFilterProc...
static pascal Boolean
aqmdf(DialogPtr dlog, EventRecord *eventp, short *ihit)
{
Boolean keep;
Boolean result;
short key;
Handle addhand;
Rect irect;
Boolean (*kfilter)(Byte);
SetPort(dlog);
result = StdFilterProc(dlog,eventp,ihit);
GetDialogItem(dlog,DAQADD,&key,&addhand,&irect);
switch ( (*eventp).what ) {
case keyDown:
case autoKey:
key = charCodeMask & (*eventp).message;
switch ( 1 + (*(DialogPeek)dlog).editField ) {
case DAQCOS:
case DAQLIF:
kfilter = dokdigit;
break;
default:
kfilter = dokgraph;
}
if ( 0 != (cmdKey&(*eventp).modifiers) ) {
keep = comkey(key,kfilter);
} else switch(key) {
case '\n':
case 3:
keep = (0 == (**(ControlHandle)addhand).contrlHilite);
break;
case Escape: // Escape or Clear
keep = result;
if (!result)
DialogDelete(dlog); // If clear just erase everything
break;
case '\b':
case '\t':
case LeftArrow:
case RightArrow:
case UpArrow:
case DownArrow:
keep = true;
break;
default:
keep = (*kfilter)(key);
}
if (!keep) {
(*eventp).what = nullEvent;
result = false;
}
break;
case activateEvt:
HiliteControl((ControlHandle)addhand,255);
}
return(result);
}
Most of this is keeping non-digits out of DAQCOS and DAQLIF
but the kluge is the activateEvt. The mainline takes care
of actually activating and deactivating the control...
+-+-+
Charles B. (Ben) Cranston <zben@ni.umd.edu>
http://www.wam.umd.edu/~zben
---------------------------
>From megawatt@noproblem.uchicago.edu (MegaWatt)
Subject: MacTCP Question
Date: Thu, 24 Aug 1995 15:58:45 GMT
Organization: University of Chicago
I have noticed that NewsWatcher uses the NewTCPIOCompletionProc routine,
but I cannot find any documentation on it. Is this a necessary routine? Is
there some documentation on it somewhere? I can't find it in the tech
notes either.
Thanks.
- --------------------------------------------------------------------
MegaWatt |
| _____ _____ _____ _ _
- AKA - | |__ / | ___ || ___ \ | | | |
| / / | |_| || |_/ / | | | |
Aaron L. Bratcher | / /__ | ___ || __/ |_| |_|
University of Chicago | |_____||_| |_||_| (_) (_)
megawatt@noproblem.uchicago.edu |
- --------------------------------------------------------------------
+++++++++++++++++++++++++++
>From scouten@uiuc.edu (Eric Scouten)
Date: Thu, 24 Aug 1995 23:52:57 -0500
Organization: Huh? What's that?
In article <megawatt-2408950958450001@fpm-mac-17.uchicago.edu>,
megawatt@noproblem.uchicago.edu (MegaWatt) wrote:
> I have noticed that NewsWatcher uses the NewTCPIOCompletionProc routine,
> but I cannot find any documentation on it. Is this a necessary routine? Is
> there some documentation on it somewhere? I can't find it in the tech
> notes either.
In general, functions whose names are New___CompletionProc aren't
documented individually. They're usually preprocessor macros which
generate the data structures that the Mixed Mode Manager needs in order to
correctly switch between 68K emulation and PowerPC native execution. You
can see the definition for it in <MacTCP.h>.
If you're targeting PowerPC processors in your build, this is a necessary
function. If and ONLY if you are sure you'll always build for 68K only,
you can leave it out. (These days, that means don't leave it out.)
-es
__________________________________________________________________________
Eric Scouten Constructor Constructor
scouten@metrowerks.com Metrowerks, Inc.
Oh, love and money almost the same: the less you make, the more you're to blame.
-John Gorka
---------------------------
End of C.S.M.P. Digest
**********************